﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using NClass.Core;
using NClass.TestHelper;
using NClass.Translations;
using System;
using System.Collections.Generic;

namespace NClass.Test.Core.Relationships
{
	[TestClass]
	public class GeneralizationRelationshipTest
	{
		private class OnAttachingTestSet : Tuple<CompositeType, CompositeType, string>
		{
			public OnAttachingTestSet(CompositeType entityTypeA, CompositeType entityTypeB, string exceptionMessage) :
				base(entityTypeA, entityTypeB, exceptionMessage)
			{
			}

		}

		private CompositeType CreateType(Model model, Type type)
		{
			if (type == typeof(StructureType))
				return model.AddStructure();
			if (type == typeof(InterfaceType))
				return model.AddInterface();
			if (type == typeof(ClassType))
				return model.AddClass();

			throw new NotImplementedException("CreateType");
		}

		[TestMethod]
		[TestCategoryAttribute("Branch Path Coverage")]
		public void OnAttaching()
		{
			// Cannot cover all branches because the OnAttaching method ends with an
			// ELSE IF statement that cannot be false once it has been reached.

			var dataSetCollection = new List<OnAttachingTestSet>();
			Language language = null;
			var model = Resolver.CreateModel(Resolver.Language.CSharp, out language);

			var baseClass = model.AddClass();
			var superClass = model.AddClass();
			model.AddGeneralization(superClass, baseClass);

			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(StructureType)), CreateType(model, typeof(StructureType)), Strings.ErrorNotAllowedChild));
			// Allow Child, Not Allow Parent
			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(ClassType)), CreateType(model, typeof(StructureType)), Strings.ErrorNotAllowedParent));
			// Allow Child, Allow Parent, Fist Already Has Base
			dataSetCollection.Add(new OnAttachingTestSet(superClass, CreateType(model, typeof(ClassType)), Strings.ErrorMultipleBases));
			// Single and Not Single
			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(ClassType)), CreateType(model, typeof(InterfaceType)), Strings.ErrorInvalidBaseType));
			// Interface Inherit from Non-Interface
			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(InterfaceType)), CreateType(model, typeof(ClassType)), Strings.ErrorInvalidBaseType));
			// Check Base Assignment Succeeded (Single to Single)
			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(ClassType)), CreateType(model, typeof(ClassType)), string.Empty));
			// Check Base Assignment Succeeded (Interface to Interface)
			dataSetCollection.Add(new OnAttachingTestSet(CreateType(model, typeof(InterfaceType)), CreateType(model, typeof(InterfaceType)), string.Empty));

			// Execute Test
			GeneralizationRelationship genRelationship = null;
			foreach (var dataSet in dataSetCollection)
			{
				try
				{
					model.AddGeneralization(dataSet.Item1, dataSet.Item2);
					// Ensure test set expects successful run
					Assert.AreEqual(dataSet.Item3, string.Empty);

					// Need to check base.
					var foundRelationship = false;
					foreach (var relationship in model.Relationships)
					{
						genRelationship = relationship as GeneralizationRelationship;

						if (genRelationship == null)
							continue;

						if (genRelationship.First == dataSet.Item1)
						{
							if (genRelationship.Second == dataSet.Item2)
							{
								foundRelationship = true;
								break;
							}
						}
					}

					if (!foundRelationship)
						Assert.Fail("Could not verify that the base was assigned correctly");
				}
				catch (Exception ex)
				{
					Assert.AreEqual(dataSet.Item3, ex.Message, ex.Message);
				}
			}
		}
	}
}
